﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Text.RegularExpressions;

namespace Release_Builder
{
    class Program
    {
        static string Source = @"";
        static int StartupDirsUp = 6;

        static List<KeyValuePair<string, string>> Sources;

        static string[] ExcludeDirs = 
        {
            @"$tf\",
            @"bin\",
            @"Demos\",
            @"obj\",
            @"Releases\",
            @"Templates\",
            @"VSTemplates\",

            @"Images\Screenshots\",
            @"Images\Logo\",
            @"Images\Tiles\",

            @"Scripts\JS\jQuery\UI\"
        };

        static string[] ExcludeNames = 
        {
            "Demo",
            "Test"
        };

        static string[] IncludeFiles = 
        {
            @"Copyright Notice.txt",
            @"MyApp.html",
            @"MyApp.min.html",

            @"Scripts\TS\Lib\TypeScriptUI.js",
            @"Scripts\TS\Lib\TypeScriptUI.min.js",
            
            @"Scripts\TS\Apps\Build_Apps.bat",

            @"Scripts\TS\Apps\MyApp.ts",
            @"Scripts\TS\Apps\MyApp.js",
            @"Scripts\TS\Apps\MyApp.min.js",
            
            @"Scripts\TS\Apps\Starters\MyAppStarter.ts",
            @"Scripts\TS\Apps\Starters\MyAppStarter.js",
            @"Scripts\TS\Apps\Starters\MyAppStarter.min.js"
        };

        static void Main(string[] args)
        {
            {
                string StartupPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                DirectoryInfo inf = new DirectoryInfo(StartupPath);
                for (int i = 0; i < StartupDirsUp; i++)
                {
                    inf = inf.Parent;
                }
                Source = inf.FullName;
                if (!Source.EndsWith("\\"))
                {
                    Source += "\\";
                }
            }

            Sources = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>( Source + @"Scripts\TS\Lib\Build\", "*.d.ts" ),
                new KeyValuePair<string, string>( Source + @"Scripts\TS\Definitions\", "*.d.ts" ),
                new KeyValuePair<string, string>( Source, "*.css" ),
                new KeyValuePair<string, string>( Source, "*.png" ),
                new KeyValuePair<string, string>( Source + @"Scripts\JS\", "*.js" ),
                new KeyValuePair<string, string>( Source + @"Scripts\TS\Sample Apps\", "*.ts" ),
                new KeyValuePair<string, string>( Source + @"Scripts\TS\Sample Apps\", "*.js" ),
                new KeyValuePair<string, string>( Source + @"Scripts\TS\Sample Apps\", "*.html" ),
                new KeyValuePair<string, string>( Source + @"Scripts\TS\Sample Apps\", "*.bat" )
            };

            if (args.Length > 0)
            {
                if (args[0] == "build")
                {
                    string LibDir = Source + @"Scripts\TS\Lib";
                    string BuildPartsDir = Source + @"Scripts\TS\Lib\Build Parts";
                    string BuildDir = Source + @"Scripts\TS\Lib\Build";

                    //if (Directory.Exists(BuildDir))
                    //{
                    //    Directory.Delete(BuildDir, true);
                    //}

                    string[] CopyFiles = Directory.GetFiles(BuildPartsDir, "*.*", SearchOption.AllDirectories);
                    foreach (string aFile in CopyFiles)
                    {
                        string destPath = aFile.Replace(BuildPartsDir, BuildDir);
                        string destFolder = destPath.Replace(destPath.Split('\\').Last(), "");
                        if (!Directory.Exists(destFolder))
                        {
                            Directory.CreateDirectory(destFolder);
                        }
                        File.Copy(aFile, destPath, true);
                    }

                    string[] AllLibFiles = Directory.GetFiles(LibDir, "*.d.ts", SearchOption.AllDirectories);
                    CopyFiles = AllLibFiles.Where(delegate(string x)
                    {
                        bool OK = true;
                        OK = !x.Contains("Classes");
                        Regex InterfaceRegex = new Regex(@"\\I[A-Z][^\.]*\.d\.ts");
                        OK = OK && (InterfaceRegex.IsMatch(x));
                        OK = OK && !x.Contains("\\Build\\");
                        return OK;
                    }).ToArray();
                    foreach (string aFile in CopyFiles)
                    {
                        string destPath = aFile.Replace(LibDir, BuildDir);
                        string destFolder = destPath.Replace(destPath.Split('\\').Last(), "");
                        if (!Directory.Exists(destFolder))
                        {
                            Directory.CreateDirectory(destFolder);
                        }
                        File.Copy(aFile, destPath, true);

                        string FileContents = File.ReadAllText(destPath);
                        //Make sure we aren't about to end up with .d.d.ts accidentally
                        FileContents = FileContents.Replace(".d.ts\" />", ".ts\" />");

                        //Replace .ts with .d.ts as is should be
                        FileContents = FileContents.Replace(".ts\" />", ".d.ts\" />");

                        FileContents = FileContents.Replace("../Definitions", "../../Definitions");

                        FileContents = FileContents.Replace("_BuildRefs.d.ts", "Refs.d.ts");

                        File.WriteAllText(destPath, FileContents);
                    }

                    string[] Files = Directory.GetFiles(BuildDir, "*.d.ts", SearchOption.AllDirectories);
                    foreach (string aFile in Files)
                    {
                        Regex InterfaceRegex = new Regex(@"\\I[A-Z][^\.]*\.d\.ts");
                        bool OK = InterfaceRegex.IsMatch(aFile);
                        
                        if (!OK)
                        {
                            string FileContents = File.ReadAllText(aFile);
                            
                            //Class files only

                            FileContents = FileContents.Replace("_BuildRefs.d.ts", "Refs.d.ts");
                            Regex RefsRegex = new Regex("\\.\\./([^/]*)/([^/]*)Refs.d.ts");
                            FileContents = RefsRegex.Replace(FileContents, "$1/$2Refs.d.ts");

                            //References need to have one dir removed so they are Build relative not Lib relative
                            //Regex InterfaceRefRegex = new Regex(@"../([^/]*)(/[^/]*)?/(I[A-Z][^\.]*\.d\.ts)");
                            //FileContents = InterfaceRefRegex.Replace(FileContents, "$1$2/$3");
                            
                            //Most recent attempt
                            //Regex InterfaceRefRegex = new Regex(@"\\.\\./([^/]*)/Interfaces/(I[A-Z][^\.]*\.d\.ts)");
                            //FileContents = InterfaceRefRegex.Replace(FileContents, "$1/Interfaces/$2");

                            string[] Lines = FileContents.Split('\n');
                            FileContents = "";
                            for (int i = 0; i < Lines.Length; i++)
                            {
                                if (Lines[i].StartsWith("/// <reference path=\""))
                                {
                                    Lines[i] = Lines[i].Trim();
                                    int offset = "/// <reference path=\"".Length;
                                    string refPart = Lines[i].Substring(offset, (Lines[i].Length - "\" />".Length) - offset);
                                    if (refPart.EndsWith("Refs.d.ts") || refPart.Contains("/Definitions/"))
                                    {
                                        //Ignore
                                    }
                                    else
                                    {
                                        string[] folders = refPart.Split('/');
                                        if (folders.Length > 2 && folders.Last()[0] == 'I')
                                        {
                                            //Remove one dir
                                            refPart = "";
                                            for (int pNum = 1; pNum < folders.Length; pNum++)
                                            {
                                                refPart += folders[pNum];
                                                if (pNum < folders.Length - 1)
                                                {
                                                    refPart += "/";
                                                }
                                            }
                                        }
                                        else
                                        {
                                            //Ignore
                                        }
                                    }

                                    Lines[i] = "/// <reference path=\"" + refPart + "\" />";
                                }

                                FileContents += Lines[i];
                                if (i < Lines.Length - 1)
                                {
                                    FileContents += "\n";
                                }
                            }

                            //FileContents = FileContents.Replace("../../Animation", "../Animation");
                            //FileContents = FileContents.Replace("../../Data", "../Data");
                            //FileContents = FileContents.Replace("../../UI", "../UI");
                            //FileContents = FileContents.Replace("../../Events", "../Events");
                            //FileContents = FileContents.Replace("../../Exceptions", "../Exceptions");
                            //FileContents = FileContents.Replace("../../Collections", "../Collections");

                            File.WriteAllText(aFile, FileContents);
                        }
                    }
                    Console.WriteLine("Build complete");
                }
                else if (args[0] == "release")
                {
                    try
                    {
                        string OutputDir = Source + @"Releases\" + args[1] + @"\";
                        if (Directory.Exists(OutputDir))
                        {
                            Directory.Delete(OutputDir, true);
                        }

                        Directory.CreateDirectory(OutputDir);

                        Console.WriteLine(OutputDir);

                        foreach (KeyValuePair<string, string> ASource in Sources)
                        {
                            string[] Files = Directory.GetFiles(ASource.Key, ASource.Value, SearchOption.AllDirectories);

                            foreach (string aFile in Files)
                            {
                                bool ignore = false;
                                foreach (string excDir in ExcludeDirs)
                                {
                                    if (aFile.Contains(Source + excDir))
                                    {
                                        ignore = true;
                                        break;
                                    }
                                }
                                if (!ignore)
                                {
                                    FileInfo inf = new FileInfo(aFile);
                                    foreach (string excName in ExcludeNames)
                                    {
                                        if (inf.Name.Contains(excName))
                                        {
                                            ignore = true;
                                            break;
                                        }
                                    }
                                }


                                if (ignore)
                                {
                                    continue;
                                }
                                else
                                {
                                    CopyFile(aFile, OutputDir);
                                }
                            }
                        }

                        foreach (string incFile in IncludeFiles)
                        {
                            string aFile = Source + incFile;
                            CopyFile(aFile, OutputDir);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }

                Console.WriteLine();
                Console.WriteLine("-------- Complete --------");
            }
            else
            {
                Console.WriteLine("Requires at least 1 start param!");
            }

            if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.WriteLine("Press enter to continue...");
                Console.ReadLine();
            }
        }

        public static void DeleteDirectory(string target_dir)
        {
            string[] files = Directory.GetFiles(target_dir, "*.*", SearchOption.AllDirectories);
            string[] dirs = Directory.GetDirectories(target_dir, "*", SearchOption.AllDirectories);

            foreach (string file in files)
            {
                File.SetAttributes(file, FileAttributes.Normal);
                File.Delete(file);
            }

            foreach (string dir in dirs)
            {
                Directory.Delete(dir, true);
            }

            Directory.Delete(target_dir, true);
        }

        public static void CopyFile(string aFile, string OutputDir)
        {
            try
            {
                string outputFile = aFile.Replace(Source, OutputDir);
                string[] dirs = outputFile.Split('\\');
                string outputDir = outputFile.Replace(dirs.Last(), "");
                if (!Directory.Exists(outputDir))
                {
                    Directory.CreateDirectory(outputDir);
                }
                File.Copy(aFile, outputFile, true);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}
